Skip to content

[front] Fix sandbox function staging reads against symlink swap (TOCTOU) - #30191

Merged
fontanierh merged 4 commits into
mainfrom
staging-integrity
Aug 10, 2026
Merged

[front] Fix sandbox function staging reads against symlink swap (TOCTOU)#30191
fontanierh merged 4 commits into
mainfrom
staging-integrity

Conversation

@fontanierh

Copy link
Copy Markdown
Contributor

Description

buildSandboxFunctionOnSandbox and getDatabaseSchemaOnSandbox stage artifacts in agent-writable /tmp dirs as agent-proxied, then read them back through the provider file API, which envd serves as root while following symlinks. Code running as the agent on the same sandbox VM could swap a staging file for a symlink to a root-only file (e.g. /run/dust/egress-secrets.json) between the exec and the read, and the root read would return that file's content to the caller or persist it as a published function bundle.

Each producing exec now appends a marker and per-file sha256 lines after the dsbx output, and the read-back content is verified against those hashes before use, failing closed on any mismatch:

  • swap before the capture: the capture itself fails (set -e; sha256sum cannot open the swapped target as agent-proxied)
  • swap after the capture: content no longer hashes equal
  • error messages never carry content, so a swapped-in file cannot leak through the error path either

Follow-ups not in this PR: same hardening for any future provider.readFile/writeFile caller under agent-writable paths, and the dsbx port-80 Host pinning issue tracked separately.

Tests

  • New staging_integrity.test.ts for the split/verify helpers.
  • New swap-detection tests in build_on_sandbox.test.ts and a new dsbx_db.test.ts covering the schema flow (match, swapped file, missing hash).
  • Full lib/api/sandbox_functions and lib/api/sandbox suites pass locally in a dust-hive env (70 + 363 tests).

Risk

Low. Only the two staging flows change; both fail closed on any anomaly (missing marker, missing hash, mismatch), so worst case is a failed publish/schema read that the model can retry. Rollback is a revert.

Deploy Plan

Standard deploy.

@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
playground Ignored Ignored Preview Aug 10, 2026 1:01pm
storybook Ignored Ignored Preview Aug 10, 2026 1:01pm

Request Review

@dust-agent dust-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding Rules LGTM \o/

@zmarouf zmarouf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I tried poking and the only thing I found was the sha256sum format that GNU based.
But the check fails closed.

buildSandboxFunctionOnSandbox and getDatabaseSchemaOnSandbox stage artifacts
in agent-writable /tmp dirs as agent-proxied, then read them back through the
provider file API, which envd serves as root while following symlinks. Code
running as the agent on the same sandbox VM could swap a staging file for a
symlink to a root-only file (e.g. /run/dust/egress-secrets.json) between the
exec and the read, and the root read would return that file's content to the
caller or persist it as a published function bundle.

Pin each artifact to the sha256 captured at the end of the producing exec and
fail closed on mismatch. A swap before the capture fails the capture itself
(set -e: sha256sum cannot open the swapped target as agent-proxied); a swap
after the capture no longer hashes equal. Error messages never carry content,
so a swapped-in file cannot leak through the error path either.
…sing hash

Review feedback: anchor the stdout split on the last full-line marker so a
model printing the marker string cannot shadow the real capture or truncate
its own output mid-stream, and include the exec stderr in the missing-hash
error so a failed capture (e.g. sha256sum denied on a swapped target) is
debuggable.
Splitting every dsbx db command's stdout at the capture marker let code the
command imports (the model-written schema file during reconcile) print a
forged envelope followed by a marker line and shadow the real envelope,
which is otherwise always the last stdout line. Gate the split on an
explicit stagingCapture flag that only db schema sets.
Fixes the format-check failure (biome requires type imports separated
from value imports).
@fontanierh
fontanierh merged commit bbfa65f into main Aug 10, 2026
42 checks passed
@fontanierh
fontanierh deleted the staging-integrity branch August 10, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants